package com.jichaoyun.task;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.jichaoyun.common.model.Result;
import com.jichaoyun.dao.mapper.*;
import com.jichaoyun.model.entity.*;
import com.jichaoyun.common.enums.MyExceptiontType;
import com.jichaoyun.common.ex.MyException;
import com.jichaoyun.model.entity.*;
import com.jichaoyun.service.*;
import com.jichaoyun.service.util.TcpUtils.TcpConnect;
import com.jichaoyun.service.util.TcpUtils.TcpUtil;

import java.io.IOException;
import java.io.OutputStream;
import java.math.RoundingMode;
import java.net.Socket;
import java.sql.Time;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.*;

import com.jichaoyun.service.util.SmsSendService;
//import com.jichaoyun.service.TcpUtils.util.TcpConnect;
//import com.jichaoyun.service.TcpUtils.util.TcpUtil;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Select;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * 多线程定时任务
 *
 * ywqqq,zz
 * @author hp-pc
 */
@Component
@EnableScheduling   // 1.开启定时任务
@EnableAsync        // 2.开启多线程
@Slf4j
public class MultiThreadScheduleTask {
    @Autowired
    private IFlowHourService flowHourService;
    @Autowired
    private IFlowDayService flowDayService;
    @Autowired
    private IFlowMonthService flowMonthService;

    @Resource
    private RealdataMapper realdataMapper;

    @Resource
    private RealdataCacheMapper realdataCacheMapper;

    @Resource
    private StationInfoMapper stationInfoMapper;

    @Resource
    private IStationInfoService stationInfoService;

    @Resource
    private FlowHourMapper flowHourMapper;

    @Resource
    private FlowMonthMapper flowMonthMapper;

    @Resource
    private FlowDayMapper flowDayMapper;

    @Resource
    private SmsCacheMapper smsCacheMapper;

    @Autowired
    private IRechargeinfoService rechargeinfoService;

    @Autowired
    private IPriceChangeService priceChangeService;

    @Autowired
    private ComErrAlarmMapper comErrAlarmMapper;
    @Autowired
    private PipelossAlarmMapper pipelossAlarmMapper;


    /**
     * 短信发送
     */
    @Scheduled(cron = "0/3 * * * * ? ")
    public void sms_send() throws Exception {
        List<SmsCache> smsCaches = smsCacheMapper.selectList(null);
        for (SmsCache smsCach : smsCaches) {
            if(smsCach!=null){
                Time sentTimeStart = new Time(Time.valueOf("08:00:00").getTime());
                Time sentTimeEnd = new Time(Time.valueOf("22:00:00").getTime());
                if("管损报警".equals(smsCach.getMessage())){

                }else{
                    StationInfo stationInfo = stationInfoMapper.selectById(smsCach.getStationNo());
                    if(stationInfo!=null){
                        sentTimeStart = Optional.ofNullable(stationInfo.getSentTimeStart()).orElse(new Time(Time.valueOf("08:00:00").getTime()));
                        sentTimeEnd = Optional.ofNullable(stationInfo.getSentTimeEnd()).orElse(new Time(Time.valueOf("22:00:00").getTime()));
                    }
                }
                LocalDateTime now = LocalDateTime.now();
                int hour = now.getHour();
                int minute = now.getMinute();
                int second = now.getSecond();
                Time time = Time.valueOf(String.format("%02d:%02d:%02d", hour, minute, second));
                //只有在规定的时间才能发送
                if (sentTimeEnd.compareTo(time)>0 && time.compareTo(sentTimeStart)>0){
                    String para = smsCach.getPara();
                    Object num = smsCach.getNum()==null ? smsCach.getNum():smsCach.getNum().toString();
                    String message = smsCach.getMessage();
                    String tempName = smsCach.getTempName();
                    String tels = smsCach.getTel().trim();
//                    if(!tels.equals("18154094192")) continue;
                    Object balance = smsCach.getBalance()==null ? smsCach.getBalance(): smsCach.getBalance().setScale(2, RoundingMode.HALF_UP).floatValue();
                    String stationName = smsCach.getStationName().trim();
                    LocalDateTime till = smsCach.getTillTime();
                    Object recharge = smsCach.getRechangeNum()==null ? smsCach.getRechangeNum(): smsCach.getRechangeNum().setScale(2, RoundingMode.HALF_UP).floatValue();
                    for(int i=0;i<tels.length();i+=11) {
                        String tel = tels.substring(i, i + 11);
                        switch (tempName) {
                            case "余额报警":
                                String s1 = SmsSendService.smsSend_balance(tel, stationName, (Float) balance);
                                if (s1.equals("OK")) {
                                    smsCacheMapper.deleteById(smsCach);
                                }
                                break;
                            case "短信正常充值":
                                String s2 = SmsSendService.smsSend_recharge(tel, stationName, (float) recharge, till, (float) balance);
                                if (s2.equals("OK")) {
                                    smsCacheMapper.deleteById(smsCach);
                                }
                                break;
                            case "直流供电提醒":
                                String s3 = SmsSendService.smsSend_dcAlarm(tel, stationName);
                                if (s3.equals("OK")) {
                                    smsCacheMapper.deleteById(smsCach);
                                }
                                break;
                            case "通讯中断提醒":
                                String s4 = SmsSendService.smsSend_comAlarm(tel, stationName);
                                if (s4.equals("OK")) {
                                    smsCacheMapper.deleteById(smsCach);
                                }
                                break;
                            case "超限报警":
                                String s5 = SmsSendService.smsSend_limitAlarm(tel, stationName, para, (String) num, message);
                                if (s5.equals("OK")) {
                                    smsCacheMapper.deleteById(smsCach);
                                }
                                break;
                            case "仪表组态报警":
                                String s6 = SmsSendService.smsSend_paraAlarm(tel, stationName);
                                if (s6.equals("OK")) {
                                    smsCacheMapper.deleteById(smsCach);
                                }
                                break;
                            case "门开报警":
                                String s7 = SmsSendService.smsSend_doorAlarm(tel, stationName);
                                if (s7.equals("OK")) {
                                    smsCacheMapper.deleteById(smsCach);
                                }
                                break;
                            default:

                        }
                    }
                }
            }

        }
    }


    /**
     * 站点的通讯中断必须放到这个地方进行超时判断
     */
    @Scheduled(cron = "0 * * * * ? ")
    @Transactional
    public void comError() throws IOException {
        List<StationInfo> allUsedStation = stationInfoService.getAllUsedStation();
        for (StationInfo stationInfo : allUsedStation) {
            Integer stationNo = stationInfo.getStationNo();
            LocalDateTime date = LocalDateTime.of(2000, 1, 1, 1, 1, 1);
            if(TcpConnect.last_comError[stationNo]==null || TcpConnect.last_comError[stationNo].equals(date) ){
                continue;
            }
            long between = ChronoUnit.SECONDS.between(TcpConnect.last_comError[stationNo], LocalDateTime.now());
            if(between>=600){
                log.info(stationInfo.getStationName()+"连接失败,10分钟未读取到数据，通信中断");
                ComErrAlarm comErrAlarm = new ComErrAlarm();
                comErrAlarm.setIsRead(false);
                comErrAlarm.setIsReadAdmin(false);
                comErrAlarm.setStation(stationNo);
                comErrAlarm.setStartTime(TcpConnect.last_comError[stationNo]);
                comErrAlarm.setInfo("仪表通信中断");
                comErrAlarmMapper.insert(comErrAlarm);
                //推送中断报警信息
                SmsSendService.int_sms_comAlarm(stationInfo.getTel(),stationInfo.getStationName(),stationNo);
                TcpConnect.last_comError[stationNo] = date;
            }
        }

    }



    /**
     * 汽费调整的逻辑
     */
    @Scheduled(cron = "0 * * * * ? ")
    @Transactional
    public void priceChange() throws IOException {
        //找到当前已经开始的汽费单价修改并且更新
        QueryWrapper<PriceChange> wrapper = new QueryWrapper<>();
        wrapper.eq("is_use",false);
        wrapper.le("start_time",LocalDateTime.now());
        List<PriceChange> priceChangeList = this.priceChangeService.getBaseMapper().selectList(wrapper);
        for(PriceChange change : priceChangeList){

            StationInfo stationInfo = this.stationInfoMapper.selectById(change.getStationId());

            change.setIsUse(true);
            if(stationInfo==null){
                log.error("站点ID " +change.getStationId() + "不存在");
                this.priceChangeService.getBaseMapper().updateById(change);
                continue;
            }
            //此时站点也存在，发送指令修改指定站点的单价
            Socket socket = TcpConnect.clientInfoMap.get(change.getStationId());
            if(socket != null){
                OutputStream outputStream = socket.getOutputStream();
                TcpUtil tcpUtil = new TcpUtil();
//                System.out.println(change.getUnitPrice().floatValue());
                tcpUtil.priceChange(change.getUnitPrice().floatValue(),outputStream,stationInfo.getComPassword(),stationInfo.getAddr());
                stationInfo.setPrice(change.getUnitPrice());
                this.priceChangeService.getBaseMapper().updateById(change);
                this.stationInfoMapper.updateById(stationInfo);
                log.info(stationInfo.getStationName()+"汽费单价修改为"+change.getUnitPrice().toString());
            }else{
                log.error(stationInfo.getStationNo()+"号站点无法连接");
            }

        }
    }

    @Scheduled(cron = "0 * * * * ? ")
    public void rechargeBank() throws Exception {
        //找到未处理的银行充值记录，进行充值
        QueryWrapper<Rechargeinfo> wrapper = new QueryWrapper<>();
        wrapper.eq("is_read",false);
        wrapper.eq("charge_type","银行充值");
        List<Rechargeinfo> rechargeinfoList = this.rechargeinfoService.getBaseMapper().selectList(wrapper);
        if(!rechargeinfoList.isEmpty()){
            for (Rechargeinfo rechargeinfo:rechargeinfoList){
                this.priceChangeService.recharge(rechargeinfo);
            }
        }
    }


    /**
     * 每小时的第 0分钟记录一次 每个站点的最近的流量是多少，
     *
     */
    @Async
    @Scheduled(cron = "0 1 * * * ?")
    public void hour() throws InterruptedException {
        //获取目前启用的站点
        List<StationInfo> stationInfoList = stationInfoService.getAllUsedStation();
        // 查询距离当前时间最近的一条实时数据，写入小时表的start
        for (StationInfo stationInfo : stationInfoList) {
            Integer stationNo = stationInfo.getStationNo();
            Realdata realdata = new Realdata();
            RealdataCache realdataCache = realdataCacheMapper.selectRecentOneByStation(stationNo);
            if(realdataCache==null) continue;
            BeanUtils.copyProperties(realdataCache,realdata);
            FlowHour flowHourLast = flowHourMapper.selectRecentOneByStation(stationNo);
            if(flowHourLast ==null){
                //如果第一次加入，则直接保存
                FlowHour flowHour = new FlowHour();
                flowHour.setStation(stationNo);

                flowHour.setRecStart(realdata.getRecordTime());
                flowHour.setFStart(realdata.getTotal());
                flowHour.setFlowStart(realdata.getFlow());
                flowHour.setTempStart(realdata.getTemp());
                flowHour.setPresStart(realdata.getPres());
                flowHour.setBalanceStart(realdata.getBalance());
                flowHour.setFreqStart(realdata.getFreq());
                flowHourService.save(flowHour);
            }else {
                //更新上一次的结束数据为当前的数据
                flowHourLast.setRecEnd(realdata.getRecordTime());
                flowHourLast.setFEnd(realdata.getTotal());
                flowHourService.updateById(flowHourLast);
                //新增当前时间节点的数据
                FlowHour flowHour = new FlowHour();
                flowHour.setStation(stationNo);
                flowHour.setRecStart(realdata.getRecordTime());
                flowHour.setFStart(realdata.getTotal());
                flowHour.setFlowStart(realdata.getFlow());
                flowHour.setTempStart(realdata.getTemp());
                flowHour.setPresStart(realdata.getPres());
                flowHour.setBalanceStart(realdata.getBalance());
                flowHour.setFreqStart(realdata.getFreq());
                flowHourService.save(flowHour);
            }
        }
    }

    /**
     * 每小时进行一次检测，是否到了某个站点的日计算时间，如果是，那么就进行结算
     *
     */
    @Async
    @Scheduled(cron = "0 1 * * * ?")
    public void day() throws InterruptedException {
        //获取目前启用的站点
        List<StationInfo> stationInfoList = stationInfoService.getAllUsedStation();

        // 查询距离当前时间最近的一条实时数据，写入小时表的start
        for (StationInfo stationInfo : stationInfoList) {
            Integer stationNo = stationInfo.getStationNo();
            //如果当前的时间是该站点的结算时间那么就进行结算到小时表
            if(LocalDateTime.now().getHour() == (int) stationInfo.getAccountHour()){
                Realdata realdata = new Realdata();
                RealdataCache realdataCache = realdataCacheMapper.selectRecentOneByStation(stationNo);
                if(realdataCache==null) continue;
                BeanUtils.copyProperties(realdataCache,realdata);
                FlowDay flowDayLast = flowDayMapper.selectRecentOneByStation(stationNo);

                if(flowDayLast ==null){
                    //如果第一次加入，则直接保存
                    FlowDay flowDay = new FlowDay();
                    flowDay.setStationNo(stationNo);
                    flowDay.setRecStart(realdata.getRecordTime());
                    flowDay.setFTotalStart(realdata.getTotal());
                    flowDay.setFlowStart(realdata.getFlow());
                    flowDay.setTempStart(realdata.getTemp());
                    flowDay.setPresStart(realdata.getPres());
                    flowDay.setAccSpend(realdata.getAccSpend());
                    flowDay.setBalance(realdata.getBalance());
                    flowDayService.save(flowDay);
                }else {
                    //更新上一次的结束数据为当前的数据
                    flowDayLast.setRecEnd(realdata.getRecordTime());
                    flowDayLast.setFTotalEnd(realdata.getTotal());
                    flowDayService.updateById(flowDayLast);
                    //新增当前时间节点的数据
                    FlowDay flowDay = new FlowDay();
                    flowDay.setStationNo(stationNo);
                    flowDay.setRecStart(realdata.getRecordTime());
                    flowDay.setFTotalStart(realdata.getTotal());
                    flowDay.setFlowStart(realdata.getFlow());
                    flowDay.setTempStart(realdata.getTemp());
                    flowDay.setPresStart(realdata.getPres());
                    flowDay.setAccSpend(realdata.getAccSpend());
                    flowDay.setBalance(realdata.getBalance());
                    flowDayService.save(flowDay);
                }
            }
        }
    }

    /**
     * 每天的0点进行一次检测，是否到了某个站点的月计算时间，如果是，那么就进行结算
     */
    @Async
    @Scheduled(cron = "0 1 0 * * ?")
    public void month() throws InterruptedException {
        //获取目前启用的站点
        List<StationInfo> stationInfoList = stationInfoService.getAllUsedStation();

        // 查询距离当前时间最近的一条实时数据，写入小时表的start
        for (StationInfo stationInfo : stationInfoList) {
            Integer stationNo = stationInfo.getStationNo();
            Integer accountDate;
            //如果当前的时间是该站点的结算时间那么就进行结算到小时表
            if(stationInfo.getAccountDate()>LocalDateTime.now().toLocalDate().lengthOfMonth()){
                 accountDate = LocalDateTime.now().toLocalDate().lengthOfMonth();
            }else{
                 accountDate = stationInfo.getAccountDate();
            }
            if(LocalDateTime.now().getDayOfMonth() == accountDate){
                Realdata realdata = new Realdata();
                RealdataCache realdataCache = realdataCacheMapper.selectRecentOneByStation(stationNo);
                if(realdataCache==null) continue;
                BeanUtils.copyProperties(realdataCache,realdata);
                FlowMonth flowMonthLast = flowMonthMapper.selectRecentOneByStation(stationNo);

                if(flowMonthLast ==null){
                    //如果第一次加入，则直接保存
                    FlowMonth flowMonth = new FlowMonth();
                    flowMonth.setStationNo(stationNo);
                    flowMonth.setRecStart(realdata.getRecordTime());
                    flowMonth.setFTotalStart(realdata.getTotal());
                    flowMonth.setFlowStart(realdata.getFlow());
                    flowMonth.setTempStart(realdata.getTemp());
                    flowMonth.setPresStart(realdata.getPres());
                    flowMonthService.save(flowMonth);
                }else {
                    //更新上一次的结束数据为当前的数据
                    flowMonthLast.setRecEnd(realdata.getRecordTime());
                    flowMonthLast.setFTotalEnd(realdata.getTotal());
                    flowMonthService.updateById(flowMonthLast);
                    //新增当前时间节点的数据
                    FlowMonth flowMonth = new FlowMonth();
                    flowMonth.setStationNo(stationNo);
                    flowMonth.setRecStart(realdata.getRecordTime());
                    flowMonth.setFTotalStart(realdata.getTotal());
                    flowMonth.setFlowStart(realdata.getFlow());
                    flowMonth.setTempStart(realdata.getTemp());
                    flowMonth.setPresStart(realdata.getPres());
                    flowMonthService.save(flowMonth);
                }
            }
        }

    }


    @Autowired
    private LineInfoMapper lineInfoMapper;

    @Autowired
    private PipelossAlarmMapper piplossAlarmMapper;


    //默认是0代表没报警，
    int[] flag = new int[100];
    @Async
    @Scheduled(cron = "0/15 * * * * ?")
    public void checkPipeLoss() {
        List<Map<String, Object>> res = new ArrayList<>();
        LambdaQueryWrapper<LineInfo> wrapper = new LambdaQueryWrapper<>();
        //屏蔽四通道表
        wrapper.ne(LineInfo::getLineNum,23);
        List<LineInfo> lineInfos = lineInfoMapper.selectList(wrapper);
        for (LineInfo lineInfo : lineInfos) {
            String lineName =  (lineInfo.getLineAlias()==null|| lineInfo.getLineAlias().equals("")) ?lineInfo.getLineName() :lineInfo.getLineAlias();
            //该路线的总表的和
            LambdaQueryWrapper<StationInfo> wp = new LambdaQueryWrapper<>();
            wp.eq(StationInfo::getUserType,0).eq(StationInfo::getLineId,lineInfo.getLineNum());
            List<StationInfo> mainStationInfoList = stationInfoMapper.selectList(wp);
            float mainTotal =0f;
            for (StationInfo stationInfo : mainStationInfoList) {
                RealdataCache realdataCache = realdataCacheMapper.selectRecentOneByStation(stationInfo.getStationNo());
                if(realdataCache==null){
                    mainTotal+=0;
                    continue;
                }
                if(realdataCache.getFlow()!=null)
                    mainTotal+=realdataCache.getFlow();
            }

            //该路线的分表的和
            LambdaQueryWrapper<StationInfo> wp1 = new LambdaQueryWrapper<>();
            wp1.eq(StationInfo::getUserType,1).eq(StationInfo::getLineId,lineInfo.getLineNum());
            List<StationInfo> subStationInfoList = stationInfoMapper.selectList(wp1);
            float subTotal =0f;
            for (StationInfo stationInfo : subStationInfoList) {
                RealdataCache realdataCache = realdataCacheMapper.selectRecentOneByStation(stationInfo.getStationNo());
                if(realdataCache==null){
                    mainTotal+=0;
                    continue;
                }
                if(realdataCache.getFlow()!=null)
                    subTotal+=realdataCache.getFlow();
            }

            Float pipelossValue = lineInfo.getAlarmValue();
            Float pipelossRate= lineInfo.getAlarmRate();
            if((mainTotal-subTotal>=pipelossValue || (mainTotal-subTotal)/mainTotal>=pipelossRate) && flag[lineInfo.getLineNum()]==0 ){
                PipeLossAlarm pipeLossAlarm = new PipeLossAlarm();
                pipeLossAlarm.setLineId(lineInfo.getLineNum());
                pipeLossAlarm.setLineName(lineName);
                pipeLossAlarm.setStartTime(LocalDateTime.now());
                pipeLossAlarm.setLossRate(pipelossRate);
                pipeLossAlarm.setLossValue(pipelossValue);
                pipeLossAlarm.setIsReadAdmin(false);
                flag[lineInfo.getLineNum()]=1;
                piplossAlarmMapper.insert(pipeLossAlarm);
                SmsSendService.in_sms_limitAlarm(lineInfo.getTels(),lineName, "管损",String.valueOf(mainTotal-subTotal)+"t/s","管损报警",lineInfo.getLineNum());

            }else if((mainTotal-subTotal<pipelossValue && (mainTotal-subTotal)/mainTotal<pipelossRate) && flag[lineInfo.getLineNum()]==1 ){
                PipeLossAlarm lastRecord = pipelossAlarmMapper.getLastRecord(lineInfo.getLineNum());
                flag[lineInfo.getLineNum()]= 0;
                if(lastRecord!=null && lastRecord.getEndTime()==null){
                    lastRecord.setEndTime(LocalDateTime.now());
                    lastRecord.setContinueTime((int) Duration.between(lastRecord.getStartTime(),LocalDateTime.now()).toMinutes());
                    piplossAlarmMapper.updateById(lastRecord);
                }
            }


        }

    }

}
